/*
 * Copyright � 2008 Nokia Corporation.
 */

// INCLUDE FILES
#include <coemain.h>
#include <aknutils.h>

#include <sudoku.mbg>
#include <Sudoku_0xE4824C7F.rsg>
#include <sudoku_svg.mbg>

#include "SudokuAppUi.h"
#include "SudokuAppView.h"
#include "SudokuGameLogic.h"
#include "SudokuGridControl.h"
#include "SudokuBtnControl.h"
#include "SudokuStatisticControl.h"
#include "GraphicEngine.h"



// ============================ MEMBER FUNCTIONS ===============================

CSudokuContainerControl* CSudokuContainerControl::NewL (const TRect& aRect )
    {
    CSudokuContainerControl* self = CSudokuContainerControl::NewLC (aRect );
    CleanupStack::Pop (self );
    return self;
    }

CSudokuContainerControl* CSudokuContainerControl::NewLC (const TRect& aRect )
    {
    CSudokuContainerControl* self = new ( ELeave ) CSudokuContainerControl;
    CleanupStack::PushL (self );
    self->ConstructL (aRect );
    return self;
    }


void CSudokuContainerControl::UseFont(CFont* aFont)
    {
    iBackBufferContext->DiscardFont();
    iBackBufferContext->UseFont(aFont);
    }

void CSudokuContainerControl::CreateFontsL()
    {
    // Remove previous ones...
    if (iFont)
        {
        iEikonEnv->ScreenDevice()->ReleaseFont(iFont);
        iFont = NULL;
        }
    if (iFont2)
        {
        iEikonEnv->ScreenDevice()->ReleaseFont(iFont2);
        iFont2 = NULL;
        }
    if (iFont3)
        {
        iEikonEnv->ScreenDevice()->ReleaseFont(iFont3);
        iFont3 = NULL;
        }

    // ...and create new font that fit into Sudoku field
    // Grid font ----------------------------------------------------
    TSize sizeInTwips = iEikonEnv->ScreenDevice()->SizeInTwips();
        
    TInt sizeOfFont = 0;
    if (sizeInTwips.iHeight > sizeInTwips.iWidth)
        {
        sizeOfFont = sizeInTwips.iWidth / 12;
        }
    else
        {
        sizeOfFont = sizeInTwips.iHeight / 12;
        }

    
    _LIT( KSeries60SansB, "Series 60 SansB" );
    TFontSpec fontSpec( KSeries60SansB, sizeOfFont );
    fontSpec.iFontStyle.SetBitmapType(EAntiAliasedGlyphBitmap);
    User::LeaveIfError(iEikonEnv->ScreenDevice()->GetNearestFontInTwips(iFont, fontSpec));

    
    // Statistic font -----------------------------------------------
    TInt sizeOfStatisticFont = sizeOfFont;
    sizeOfStatisticFont -= sizeOfStatisticFont / 4;
    TFontSpec fontSpec2( KSeries60SansB, sizeOfStatisticFont );
    fontSpec2.iFontStyle.SetBitmapType(EAntiAliasedGlyphBitmap);
    User::LeaveIfError(iEikonEnv->ScreenDevice()->GetNearestFontInTwips(iFont2, fontSpec2));

    sizeOfStatisticFont = sizeOfFont / 2;
    TFontSpec fontSpec3( KSeries60SansB, sizeOfStatisticFont );
    fontSpec3.iFontStyle.SetBitmapType(EAntiAliasedGlyphBitmap);
    User::LeaveIfError(iEikonEnv->ScreenDevice()->GetNearestFontInTwips(iFont3, fontSpec3));
    }


void CSudokuContainerControl::ConstructL (const TRect& /*aRect*/)
    {
    // Create a window for this application view
    CreateWindowL();

    EnableDragEvents();
    
    iOptionsTxt = iEikonEnv->AllocReadResourceAsDes16L(R_OPTIONS);
    iSelectTxt = iEikonEnv->AllocReadResourceAsDes16L(R_SELECT);
    iBackTxt = iEikonEnv->AllocReadResourceAsDes16L(R_BACK);
    iExitTxt = iEikonEnv->AllocReadResourceAsDes16L(R_EXIT);
    
    iGameLogic = CSudokuGameLogic::NewL();

    iGraphicEngine = static_cast<CSudokuAppUi*>(iEikonEnv->EikAppUi())->GraphicEngine();
    iAppUi = static_cast<CSudokuAppUi*>(iEikonEnv->EikAppUi());

    InitComponentArrayL();
    
    // Create child components
    TRect staticRect = TRect(TPoint(0,0),TSize(0,0));
    iStatisticControl = CSudokuStatisticControl::NewL(*this,staticRect,iBackBufferContext);
    Components().AppendLC(iStatisticControl);
    CleanupStack::Pop(iStatisticControl);

    TRect gridRect = TRect(TPoint(0,0),TSize(0,0));
    iGridControl = CSudokuGridControl::NewL(*this,gridRect,iBackBufferContext);                
    Components().AppendLC(iGridControl);
    CleanupStack::Pop(iGridControl);
    
    TRect btnRect = TRect(TPoint(0,0),TSize(0,0));
    iBtnControl = CSudokuBtnControl::NewL(*this,btnRect,iBackBufferContext);
    iBtnCtrlRect = btnRect; // default size
    iBtnControl->MakeVisible(EFalse);
    Components().AppendLC(iBtnControl);
    CleanupStack::Pop(iBtnControl);

    iSudokuMenu = CSudokuMenuControl::NewL(*this,iBackBufferContext);
    iSudokuMenu->SetObserver(this);
    HBufC16* menuText = iEikonEnv->AllocReadResourceAsDes16LC(R_MENU_RESTART);
    iSudokuMenu->AddMenuItemL(*menuText);
    CleanupStack::PopAndDestroy(menuText); menuText = NULL;
    menuText = iEikonEnv->AllocReadResourceAsDes16LC(R_MENU_NEWGAME);
    iSudokuMenu->AddMenuItemL(*menuText);
    CleanupStack::PopAndDestroy(menuText); menuText = NULL;
    menuText = iEikonEnv->AllocReadResourceAsDes16LC(R_MENU_EXIT);
    iSudokuMenu->AddMenuItemL(*menuText);
    CleanupStack::PopAndDestroy(menuText); menuText = NULL;
    iSudokuMenu->MakeVisible(EFalse);
    Components().AppendLC(iSudokuMenu);
    CleanupStack::Pop(iSudokuMenu);
    
    // Set control rect
    SetExtentToWholeScreen();
    
    ActivateL();
    
    StartFrameUpdateL(EContinuouslyScreenDrawing,DELAY);
    }


void CSudokuContainerControl::CreateBackBufferL()
    {
    // create back buffer bitmap
    iBackBuffer = new (ELeave) CFbsBitmap;
    User::LeaveIfError( iBackBuffer->Create(Size(),iEikonEnv->DefaultDisplayMode()));
    
    // create back buffer graphics context
    iBackBufferDevice = CFbsBitmapDevice::NewL(iBackBuffer);
    User::LeaveIfError(iBackBufferDevice->CreateContext(iBackBufferContext));
    iBackBufferContext->SetPenStyle(CGraphicsContext::ESolidPen);
    iBackBufferSize = iBackBuffer->SizeInPixels();
    }

void CSudokuContainerControl::ReleaseBackBuffer()
    {
    if (iBackBufferContext)
        {
        delete iBackBufferContext;
        iBackBufferContext = NULL;
        }
    if (iBackBufferDevice)
        {
        delete iBackBufferDevice;
        iBackBufferDevice = NULL;
        }
    if (iBackBuffer)
        {
        delete iBackBuffer;
        iBackBuffer = NULL;
        }
    iBackBufferSize = TSize(0, 0);
    }


void CSudokuContainerControl::HandleResourceChange(TInt aType)
    {
    CCoeControl::HandleResourceChange( aType );
    if ( aType==KEikDynamicLayoutVariantSwitch )
        {        
        SetExtentToWholeScreen();
        }
    }

CSudokuContainerControl::CSudokuContainerControl ( )
    {
    // No implementation required
    }

CSudokuContainerControl::~CSudokuContainerControl ( )
    {
    StopFrameUpdate();
    delete iPeriodic;

    delete iGameLogic;
    
    ReleaseBackBuffer();

    iEikonEnv->ScreenDevice()->ReleaseFont(iFont);
    iEikonEnv->ScreenDevice()->ReleaseFont(iFont2);
    iEikonEnv->ScreenDevice()->ReleaseFont(iFont3);
    
    delete iOptionsTxt;
    delete iBackTxt;
    delete iExitTxt;
    delete iSelectTxt;
    }

void CSudokuContainerControl::StartFrameUpdateL(EAnimationType aType, TInt startDelay)
    {
    iAnimationType = aType;
    iCleanConfictsCounter = -1;
    if (!iPeriodic)
        {
        iPeriodic = CPeriodic::NewL(CActive::EPriorityIdle);
        }
    if (!iPeriodic->IsActive())
        {
        iPeriodic->Start(TTimeIntervalMicroSeconds32(startDelay), DELAY, TCallBack(CSudokuContainerControl::DoFrame, this));
        }
    }

void CSudokuContainerControl::StopFrameUpdate()
    {
    if (iPeriodic)
        {
        iPeriodic->Cancel();
        }
    iAnimationType = ENoType;
    }

TInt CSudokuContainerControl::DoNewGame(TAny* aObj)
    {
    CSudokuContainerControl* self = static_cast<CSudokuContainerControl*>(aObj);
    self->GameLogic()->NewGameL();
    self->GameLogic()->SetBoardItemRects(self->iGridControl->Rect());
    self->StatisticControl()->ResetGameTimer();
    self->StatisticControl()->UpdateData();
    self->StartFrameUpdateL(EContinuouslyScreenDrawing,START_DELAY);
    return 0;
    }

TInt CSudokuContainerControl::DoFrame(TAny* aObj)
    {
    static_cast<CSudokuContainerControl*>(aObj)->DoDraw();
    return 1;
    }

void CSudokuContainerControl::DoDraw()
    {
    switch (iAnimationType)
        {
        case ENoType:
            {
            // Does nothing
            break;
            }
        case EContinuouslyScreenDrawing:
            {
            // Update statistic control data
            if (iStatisticControl)
                {
                iStatisticControl->UpdateData();
                }

            // Value conflict check
            if (iGameLogic->IsConflict())
                {
                // Reset conflict visible time counter
                iCleanConfictsCounter = 0;
                // Reset conflict
                iGameLogic->ResetConflict();
                // Reset cell animation
                iGridControl->ResetCellAnim();
                }
            else
                {
                // Update cell animation
                iGridControl->UpdateCellAnim();
                }
            // Check conflict visible time counter
            if(iCleanConfictsCounter > 40)
                {
                // Shown enught, time to clean confict items
                iGameLogic->CleanConflicts();
                iCleanConfictsCounter = -1;
                }
            if (iCleanConfictsCounter != -1)
                {
                iCleanConfictsCounter++;
                }

            DrawNow();
            break;
            }
        default:
            {
            break;
            }
        };
    }

void CSudokuContainerControl::Draw (const TRect& /*aRect*/) const
    {
    CWindowGc& gc = SystemGc();
    // Copy backbuffer into the screen
    gc.BitBlt(TPoint(0, 0), iBackBuffer);
    }

void CSudokuContainerControl::DrawBackground()
    {
    if (!iBackBufferContext)
        {
        return;
        }

    // Draw background
    TRect itemRect = TRect(TPoint(0,0),Rect().Size());
    iBackBufferContext->BitBlt(itemRect.iTl,
                       iGraphicEngine->Bitmap(EMbmSudokuBackground),
                       itemRect);

    // Terminal portrait
    // Draw logo
    TRect logoRect = TRect(TPoint(0,0),iLogoRect.Size());
    iBackBufferContext->BitBltMasked(iLogoRect.iTl,
                       iGraphicEngine->BitmapSVG(EMbmSudoku_svgLogo),
                       logoRect,
                       iGraphicEngine->BitmapSVG(EMbmSudoku_svgLogo_mask),
                       EFalse);
    
    
    // CBA strings
    UseFont(iFont2);
    TPoint point = iOptionsCbaPoint.iTl;
    point.iY += iOptionsCbaPoint.Height();
    iBackBufferContext->SetPenColor(KRgbWhite);
    // Options / Select
    if (iAppUi->CbaVisible(EAknSoftkeyOptions))
        {
        iBackBufferContext->DrawText(*iOptionsTxt,point);
        }
    else if (iAppUi->CbaVisible(EAknSoftkeySelect))
        {
        iBackBufferContext->DrawText(*iSelectTxt,point);
        }
    // Exit / Back
    if (iAppUi->CbaVisible(EAknSoftkeyBack) || iAppUi->CbaVisible(EAknSoftkeyCancel))
        {
        point = iBackCbaPoint.iTl;
        point.iY += iBackCbaPoint.Height();
        iBackBufferContext->DrawText(*iBackTxt,point);
        }
    else if (iAppUi->CbaVisible(EAknSoftkeyExit))
        {
        point = iExitCbaPoint.iTl;
        point.iY += iExitCbaPoint.Height();
        iBackBufferContext->DrawText(*iExitTxt,point);
        }
    }

void CSudokuContainerControl::CbaSizeChanged()
    {
    TInt txtHeight = iFont2->HeightInPixels();
    TInt txtWidth = 0;
    TRect rect = Rect();
    
    if (iAppUi->iCbaPosition == AknLayoutUtils::EAknCbaLocationBottom)
        {
        // Terminal portrait

        // Calculate Option item position
        iOptionsCbaPoint.iTl.iY = rect.Height() - txtHeight*2 - 5;
        iOptionsCbaPoint.iTl.iX = 5;
        iOptionsCbaPoint.SetSize(TSize(rect.Width()/5,txtHeight*2));
        
        // Calculate Back or Exit item position
        if (iAppUi->CbaVisible(EAknSoftkeyBack) || iAppUi->CbaVisible(EAknSoftkeyCancel))
            {
            txtWidth = iFont2->TextWidthInPixels(*iBackTxt);
            iBackCbaPoint.iTl.iY = rect.Height() - txtHeight*2 - 5;
            iBackCbaPoint.iTl.iX = rect.Width() - txtWidth - 5;
            iBackCbaPoint.SetSize(TSize(rect.Width()/5,txtHeight*2));
            }
        else
            {
            txtWidth = iFont2->TextWidthInPixels(*iExitTxt);
            iExitCbaPoint.iTl.iY = rect.Height() - txtHeight*2 - 5;
            iExitCbaPoint.iTl.iX = rect.Width() - txtWidth - 5;
            iExitCbaPoint.SetSize(TSize(rect.Width()/5,txtHeight*2));
            }
        }
    else
        {
        // Terminal landscape
        if (iAppUi->CbaVisible(EAknSoftkeyOptions))
            {
            txtWidth = iFont2->TextWidthInPixels(*iOptionsTxt);
            }
        else
            {
            txtWidth = iFont2->TextWidthInPixels(*iSelectTxt);
            }
        
        if (iAppUi->IsOptionsButtonOnTop())
            {
            // Calculate Option item position
            iOptionsCbaPoint.iTl.iY = 5;
            iOptionsCbaPoint.iTl.iX = rect.Width() - txtWidth - 5;
            iOptionsCbaPoint.SetSize(TSize(rect.Width()/5,txtHeight));

            // Calculate Back or Exit item position
            if (iAppUi->CbaVisible(EAknSoftkeyBack) || iAppUi->CbaVisible(EAknSoftkeyCancel))
                {
                txtWidth = iFont2->TextWidthInPixels(*iBackTxt);
                iBackCbaPoint.iTl.iY = rect.Height() - txtHeight - 5;
                iBackCbaPoint.iTl.iX = rect.Width() - txtWidth - 5;
                iBackCbaPoint.SetSize(TSize(rect.Width()/5,txtHeight));
                }
            else
                {
                txtWidth = iFont2->TextWidthInPixels(*iExitTxt);
                iExitCbaPoint.iTl.iY = rect.Height() - txtHeight - 5;
                iExitCbaPoint.iTl.iX = rect.Width() - txtWidth - 5;
                iExitCbaPoint.SetSize(TSize(rect.Width()/5,txtHeight));
                }
            }
        else
            {
            // Calculate Option item position
            iOptionsCbaPoint.iTl.iY = rect.Height() - txtHeight - 5;
            iOptionsCbaPoint.iTl.iX = rect.Width() - txtWidth - 5;
            iOptionsCbaPoint.SetSize(TSize(rect.Width()/5,txtHeight));

            // Calculate Back or Exit item position
            if (iAppUi->CbaVisible(EAknSoftkeyBack) || iAppUi->CbaVisible(EAknSoftkeyCancel))
                {
                txtWidth = iFont2->TextWidthInPixels(*iBackTxt);
                iBackCbaPoint.iTl.iY = 5;
                iBackCbaPoint.iTl.iX = rect.Width() - txtWidth - 5;
                iBackCbaPoint.SetSize(TSize(rect.Width()/5,txtHeight));
                }
            else
                {
                txtWidth = iFont2->TextWidthInPixels(*iExitTxt);
                iExitCbaPoint.iTl.iY = 5;
                iExitCbaPoint.iTl.iX = rect.Width() - txtWidth - 5;
                iExitCbaPoint.SetSize(TSize(rect.Width()/5,txtHeight));
                }
            }
        }
    }



void CSudokuContainerControl::SizeChanged ( )
    {
    // Delete back buffer and create a new one with new size
    ReleaseBackBuffer();
    CreateBackBufferL();

    // Update background picture size
    TSize size = Rect().Size();
    iGraphicEngine->SetBitmapSize(EMbmSudokuBackground,size);
    
    // Update font sizes
    CreateFontsL();
    
    
    // Calculate rect to CSudokuGridControl and CBtnControl
    if (iGridControl && iBtnControl)
        {
        TRect rect = Rect();
        // Set grid control width/height to 1:1
        if (rect.Width() > rect.Height())
            {
            // Terminal landscape
            rect.SetWidth(rect.Height());
            // If there is space center GridControl and StatisticControl
            // that width is half of the GridControl
            if (Rect().Width()>rect.Width()*1.5)
                {
                // Statistic is half of the grid and set them center on screen
                TInt xOffset = (Rect().Width() - rect.Width()*1.5) / 2;
                rect.Move(xOffset,0);
                rect.Shrink(10,10);
                }
            else
                {
                // Minor space for statistic
                rect.Shrink(10,10);
                }
            // (Nokia E71) If in landscape CBA buttons are bottom we need to shrink
            // sudoku grid more
            if (iAppUi->iCbaPosition == AknLayoutUtils::EAknCbaLocationBottom)
                {
                rect.Shrink(10,10);
                }
            }
        else
            {
            // Terminal portrait
            rect.SetHeight(rect.Width());
            TInt yOffset = (Rect().Height() - rect.Height()) / 2;
            rect.Move(0,yOffset);
            rect.Shrink(10,10);
            }
        iGridControl->SetRect(rect);
    
        
        // Calculate rect to CSudokuBtnControl
        TRect btnRect = iGridControl->Rect();
        btnRect.SetHeight(btnRect.Height()/2);
        btnRect.SetWidth(btnRect.Width()/2);
        btnRect.Grow(10,10);
        iBtnControl->SetRect(btnRect);
        iBtnCtrlRect = btnRect;
        if (iBtnControl->IsVisible())
            {
            CalBtnCtrlPosition();
            }
        }

    
    // Calculate CBA button positions
    CbaSizeChanged();
    
    // Calculate rect to CSudokuStatisticControl
    if (iStatisticControl && iGridControl)
        {
        TInt txtWidth = iFont2->TextWidthInPixels(*iOptionsTxt) + 5;
        TInt txtHeight = iFont2->HeightInPixels();
        TRect rect = Rect();
        if (rect.Width() > rect.Height())
            {
            // Terminal landscape
            TInt width = iGridControl->Rect().Width()/2;
            if (iGridControl->Rect().iBr.iX + width >Rect().Width())
                {
                // Still too wide
                width = Rect().Width() - iGridControl->Rect().iBr.iX; 
                }
            TInt height = txtHeight * 7;
            TPoint tl(iGridControl->Rect().iBr.iX,(rect.Height() - height) / 2);
            TRect sRect = TRect(tl,TSize(width,height));
            sRect.Shrink(4,0);
            iStatisticControl->SetRect(sRect);
            }
        else
            {
            // Terminal portrait
            TInt width = rect.Width() - txtWidth * 2;
            TInt height = rect.Height() - iGridControl->Rect().iBr.iY;
            TPoint tl((rect.Width()-width)/2,iGridControl->Rect().iBr.iY);
            TRect sRect = TRect(tl,TSize(width,height));
            sRect.Shrink(10,0);
            iStatisticControl->SetRect(sRect);
            }
        }

    
    // Calculate logo rect
    if (iGridControl)
        {
        if (iAppUi->iCbaPosition == AknLayoutUtils::EAknCbaLocationBottom)
            {
            // Portrait
            if (Rect().Width() > Rect().Height())
                {
                // Wide portrait, (Nokia E71)
                TSize size = TSize(iStatisticControl->Rect().Width(),iStatisticControl->Rect().Width()/4);
                TPoint tl = iGridControl->Rect().iBr;
                tl.iY = iStatisticControl->Rect().iTl.iY / 2;
                tl.iX = iStatisticControl->Rect().iTl.iX;            
                iLogoRect.SetRect(tl,size);
                iGraphicEngine->SetSVGBitmapSize(EMbmSudoku_svgLogo,iLogoRect.Size());
                }
            else
                {
                // Normal portrait
                iLogoRect.SetRect(Rect().iTl,TSize(Rect().Width(),iGridControl->Rect().iTl.iY));
                iLogoRect.Shrink(5,5);
                iGraphicEngine->SetSVGBitmapSize(EMbmSudoku_svgLogo,iLogoRect.Size());
                }
            }
        else
            {
            // Landscape
            TSize size = TSize(iStatisticControl->Rect().Width(),iStatisticControl->Rect().Width()/4);
            TPoint tl = iGridControl->Rect().iBr;
            tl.iY = iStatisticControl->Rect().iTl.iY / 2;
            tl.iX = iStatisticControl->Rect().iTl.iX;            
            iLogoRect.SetRect(tl,size);
            iGraphicEngine->SetSVGBitmapSize(EMbmSudoku_svgLogo,iLogoRect.Size());
            }
        }

    
    // Calculate menu rect
    if (iSudokuMenu && iGridControl)
        {
        // Use menu minimum size
        TPoint menuTl = iGridControl->Rect().Center();
        TSize minSize = iSudokuMenu->MiniSizeNeeded();
        menuTl.iY -= minSize.iHeight /2;
        menuTl.iX -= minSize.iWidth /2;
        TRect menuRect = TRect(menuTl,minSize);
        
        // Make menu bigger
        TInt sizeWidthDiff = iGridControl->Rect().Width() - minSize.iWidth;
        TInt sizeHeightDiff = iGridControl->Rect().Height() - minSize.iWidth;
        menuRect.Grow(sizeWidthDiff/6,sizeHeightDiff/6);
        iSudokuMenu->SetRect(menuRect);
        }

    
    // Update backbuffer
    DrawBackground();
    }


void CSudokuContainerControl::CalBtnCtrlPosition()
    {
    // Update CBtnControl position when user opens it
    TPoint p = iGridControl->Rect().Center();
    p.iX -= iBtnCtrlRect.Width() / 2;
    p.iY -= iBtnCtrlRect.Height() / 2;
    
    // Set new rect
    iBtnCtrlRect = TRect(p,iBtnCtrlRect.Size());
    iBtnControl->SetRect(iBtnCtrlRect);
    }

#ifndef __WINS__
TCoeInputCapabilities CSudokuContainerControl::InputCapabilities() const
    {
    return TCoeInputCapabilities(TCoeInputCapabilities::EWesternNumericIntegerPositive
            | TCoeInputCapabilities::ENavigation);
    }
#endif

TKeyResponse CSudokuContainerControl::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType)
    {
    // Key down
    TKeyResponse ret = EKeyWasNotConsumed;
    
    if (aType == EEventKeyDown)
        {
        switch (aKeyEvent.iScanCode)
            {
            case EStdKeyUpArrow:
                {
                if (iBtnControl && iBtnControl->IsVisible())
                    {
                    ret = iBtnControl->OfferKeyEventL(aKeyEvent,aType);
                    }
                else if (iSudokuMenu && iSudokuMenu->IsVisible())
                    {
                    ret = iSudokuMenu->OfferKeyEventL(aKeyEvent,aType);
                    }
                else if (iGridControl)
                    {
                    ret = iGridControl->OfferKeyEventL(aKeyEvent,aType);
                    }
                break;
                }
            case EStdKeyDownArrow:
                {
                if (iBtnControl && iBtnControl->IsVisible())
                    {
                    ret = iBtnControl->OfferKeyEventL(aKeyEvent,aType);
                    }
                else if (iSudokuMenu && iSudokuMenu->IsVisible())
                    {
                    ret = iSudokuMenu->OfferKeyEventL(aKeyEvent,aType);
                    }
                else if (iGridControl)
                    {
                    ret = iGridControl->OfferKeyEventL(aKeyEvent,aType);
                    }
                break;
                }
            case EStdKeyLeftArrow:
                {
                if (iBtnControl && iBtnControl->IsVisible())
                    {
                    ret = iBtnControl->OfferKeyEventL(aKeyEvent,aType);
                    }
                else if (iSudokuMenu && iSudokuMenu->IsVisible())
                    {
                    ret = iSudokuMenu->OfferKeyEventL(aKeyEvent,aType);
                    }
                else if (iGridControl)
                    {
                    ret = iGridControl->OfferKeyEventL(aKeyEvent,aType);
                    }
                break;
                }
            case EStdKeyRightArrow:
                {
                if (iBtnControl && iBtnControl->IsVisible())
                    {
                    ret = iBtnControl->OfferKeyEventL(aKeyEvent,aType);
                    }
                else if (iSudokuMenu && iSudokuMenu->IsVisible())
                    {
                    ret = iSudokuMenu->OfferKeyEventL(aKeyEvent,aType);
                    }
                else if (iGridControl)
                    {
                    ret = iGridControl->OfferKeyEventL(aKeyEvent,aType);
                    }
                break;
                }
            case EStdKeyDevice0: // Options, CBA
                {
                if (!iSudokuMenu->IsVisible() && !iBtnControl->IsVisible())
                    {
                    iSudokuMenu->MakeVisible(ETrue);
                    ret = EKeyWasConsumed;
                    }
                else if (iSudokuMenu->IsVisible())
                    {
                    ret = iSudokuMenu->OfferKeyEventL(aKeyEvent,aType);
                    }
                else if (iBtnControl->IsVisible())
                    {
                    ret = iBtnControl->OfferKeyEventL(aKeyEvent,aType);
                    }
                break;
                }
            case EStdKeyDevice1: // Exit, CBA
                {
                if (iSudokuMenu->IsVisible())
                    {
                    iSudokuMenu->MakeVisible(EFalse);
                    ret = EKeyWasConsumed;
                    }
                else if (iBtnControl->IsVisible())
                    {
                    iBtnControl->MakeVisible(EFalse);
                    ret = EKeyWasConsumed;
                    }
                else
                    {
                    static_cast<CSudokuAppUi*>(iEikonEnv->EikAppUi())->HandleCommandL(EEikCmdExit);
                    return EKeyWasConsumed;
                    }
                }
            case EStdKeyDevice3: // Center button, CBA
                {
                if (iBtnControl && iBtnControl->IsVisible())
                    {
                    ret = iBtnControl->OfferKeyEventL(aKeyEvent,aType);
                    }
                else if (iSudokuMenu && iSudokuMenu->IsVisible())
                    {
                    ret = iSudokuMenu->OfferKeyEventL(aKeyEvent,aType);
                    }
                else if (iGridControl)
                    {
                    // Set CBtnControl position
                    CalBtnCtrlPosition();
                    // Handle center CBA event
                    ret = iGridControl->OfferKeyEventL(aKeyEvent,aType);
                    }
                
                break;
                }
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
            case EStdKeyBackspace:
                {
                if (iBtnControl)
                    {
                    ret = iBtnControl->OfferKeyEventL(aKeyEvent,aType);
                    }
                break;
                }
            default:
                {
                break;
                }
            };
        }

    return ret;
    }


void CSudokuContainerControl::MenuItemSelected(TInt aIndex)
    {
    switch (aIndex)
        {
        case 0: // Restart
            {
            StopFrameUpdate();
            iGameLogic->RestartGame();
            iStatisticControl->ResetGameTimer();
            iStatisticControl->UpdateData();
            StartFrameUpdateL(EContinuouslyScreenDrawing,START_DELAY);
            break;
            }
        case 1: // New Game
            {
            StopFrameUpdate();
            iGameLogic->NewGameL();
            iGameLogic->SetBoardItemRects(iGridControl->Rect());
            iStatisticControl->ResetGameTimer();
            iStatisticControl->UpdateData();
            StartFrameUpdateL(EContinuouslyScreenDrawing,START_DELAY);
            break;
            }
        case 2: // Exit
            {
            static_cast<CSudokuAppUi*>(iEikonEnv->EikAppUi())->HandleCommandL(EEikCmdExit);
            return;
            }
        default:
            {
            break;
            }
        }
    }


void CSudokuContainerControl::HandlePointerEventL(const TPointerEvent& aPointerEvent)
    {
    // CBA pointing
    if (aPointerEvent.iType == TPointerEvent::EButton1Down)
        {
        // Handle Options / Select CBA
        if (iOptionsCbaPoint.Contains(aPointerEvent.iPosition) && iAppUi->CbaVisible(EAknSoftkeyOptions))
            {
            iBtnControl->MakeVisible(EFalse);
            if (iSudokuMenu)
                {
                iSudokuMenu->MakeVisible(ETrue);
                }
            }
        else if (iOptionsCbaPoint.Contains(aPointerEvent.iPosition) && iAppUi->CbaVisible(EAknSoftkeySelect))
            {
            if (iBtnControl->IsVisible())
                {
                iBtnControl->HitActiveNumber();
                }
            else if (iSudokuMenu->IsVisible())
                {
                iSudokuMenu->HitActimeMenuItem();
                }
            }
        else
            {
            // Handle Exit / Back CBA
            if (iExitCbaPoint.Contains(aPointerEvent.iPosition))
                {
                if (iAppUi->CbaVisible(EAknSoftkeyExit))
                    {
                    static_cast<CSudokuAppUi*>(iEikonEnv->EikAppUi())->HandleCommandL(EEikCmdExit);
                    return;
                    }
                }
            if (iBackCbaPoint.Contains(aPointerEvent.iPosition))
                {
                if (iAppUi->CbaVisible(EAknSoftkeyBack) || iAppUi->CbaVisible(EAknSoftkeyCancel))
                    {
                    if (iSudokuMenu)
                        {
                        iSudokuMenu->MakeVisible(EFalse);
                        }
                    if (iSudokuMenu)
                        {
                        iSudokuMenu->MakeVisible(EFalse);
                        }
                    }
                }
            }
        }

    // Hide CBtnControl if needed
    if (iBtnControl && iBtnControl->IsVisible() &&
            !iBtnControl->Rect().Contains(aPointerEvent.iPosition))
        {
        iBtnControl->MakeVisible(EFalse);
        }

    // Prepare CBtnControl position before showing it again
    if (aPointerEvent.iType == TPointerEvent::EButton1Down &&
            iGridControl->Rect().Contains(aPointerEvent.iPosition))
        {
        if (!iBtnControl->IsVisible())
            {
            CalBtnCtrlPosition();
            }
        }
    
    // Then handle child control pointer event handling
    CCoeControl::HandlePointerEventL(aPointerEvent);
    }







